/**
 * TreeCategoriesPane.java
 * @author: liuex
 * 2008-1-9 ����08:27:55
 *
 * note: 
 */
package org.lex.swing.prefs;

import java.awt.BorderLayout;
import java.awt.Component;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

import javax.swing.JScrollPane;
import javax.swing.JTree;
import javax.swing.ListSelectionModel;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeCellRenderer;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreeNode;
import javax.swing.tree.TreePath;

import org.lex.swing.Swings;
import org.lex.utils.BinarySearch;
import org.lex.utils.text.Splitter;


public class TreeCategoriesModel extends CategoriesModel {
	private JTree tree = null;
	private DefaultTreeModel treeModel = null;
	private DefaultMutableTreeNode root = null;

	public static void main(String[] args) {
		TreeCategoriesModel tree = new TreeCategoriesModel();
		String[] tests = { "a.b", "b", "a.c", "a.c.d", "ad.a", "v.a.b.c.d.e", "v.a.1", "v.a.5", "v.a.7", "v.a.11" };
		List<String> t = Arrays.asList(tests);
		Collections.shuffle(t);
		tests = t.toArray(new String[0]);
		for (int i = 0; i < tests.length; i++)
			tree.addNode(Splitter.DotSplitter.split(tests[i]));
		Swings.expandAll(tree.getTree());
		tree.addCategoryChangedListener(new PropertyChangeListener() {
			public void propertyChange(PropertyChangeEvent e) {
				System.out.println(e.getNewValue());
			}
		});
		Swings.show(tree);
	}

	public TreeCategoriesModel() {
		super();
		this.root = new DefaultMutableTreeNode("Root");
		this.treeModel = new DefaultTreeModel(root);
		this.initalize();
	}

	public void addCategories(Category... categories) {
		if (null == categories || 0 == categories.length)
			return;
		for (int i = 0; i < categories.length; i++)
			this.addNode(Splitter.DotSplitter.split(categories[i].getTitle()));
		this.getTree().expandRow(0);
	}

	private void addNode(String[] path) {
		if (null == path || 0 == path.length)
			return;
		int i = 0;
		DefaultMutableTreeNode current = root;
		while (i < path.length) {
			String name = path[i];
			DefaultMutableTreeNode node = (DefaultMutableTreeNode) findChild(current, name);
			if (null == node) {
				// add "name" to tree;
				node = new DefaultMutableTreeNode(name);
				// ʹ�ö��ַ���������λ�ã������һ���������
				int pos = BinarySearch.search(current, name);
				if (pos > 0)
					System.err.println("WARNING: " + name + " already exist!");
				if (pos < 0)
					pos = -pos - 1;
				current.insert(node, pos);
				treeModel.nodeStructureChanged(current);
			}
			current = node;
			i++;
		}
	}

	private TreeNode findChild(TreeNode root, String child) {
		int count = root.getChildCount();
		for (int i = 0; i < count; i++) {
			TreeNode node = root.getChildAt(i);
			if (node.toString().equals(child))
				return node;
		}
		return null;
	}

	private JTree getTree() {
		if (null == tree) {
			tree = new JTree(treeModel);
			tree.getSelectionModel().setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
			tree.setToggleClickCount(1);
			tree.setShowsRootHandles(true);
			tree.setRootVisible(false);
			tree.setCellRenderer(new NoIconRenderer());
			tree.getSelectionModel().addTreeSelectionListener(new TreeSelectionListener() {
				public void valueChanged(TreeSelectionEvent e) {
					TreePath tp = e.getNewLeadSelectionPath();
					if (null == tp)
						return;
					Object[] path = tp.getPath();
					if (1 == path.length)
						return;// just contains the root node
					StringBuilder buf = new StringBuilder();
					for (int i = 1; i < path.length; i++) {
						buf.append(path[i].toString());
						if (i < path.length - 1)
							buf.append('.');
					}
					fireSelectedCategoryChanged(buf.toString());
				}
			});
			// tree.addMouseListener( new MouseAdapter(){
			// public void mouseClicked( MouseEvent e )
			// {
			// TreePath tp = tree.getPathForLocation( e.getX(), e.getY() );
			// if( null == tp )
			// return;
			// Object[] path = tp.getPath();
			// if( 1 == path.length )
			// return;// just contains the root node
			// StringBuilder buf = new StringBuilder();
			// for( int i = 1; i < path.length; i++ )
			// {
			// buf.append( path[i].toString() );
			// if( i < path.length - 1 )
			// buf.append( '.' );
			// }
			// fireSelectedCategoryChanged( buf.toString() );
			// }
			// } );
		}
		return tree;
	}

	private void initalize() {
		this.setLayout(new BorderLayout());
		JScrollPane scroll = new JScrollPane(this.getTree());
		this.add(scroll, BorderLayout.CENTER);
	}

	static class NoIconRenderer extends DefaultTreeCellRenderer {
		public Component getTreeCellRendererComponent(JTree tree, Object value, boolean sel, boolean expanded, boolean leaf, int row, boolean hasFocus) {
			super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf, row, hasFocus);
			this.setIcon(null);
			return this;
		}
	}
}
